package transport

import (
	"context"

	"gitee.com/jason_elva8325/micro-quickstart/common"
	"gitee.com/jason_elva8325/micro-quickstart/endpoint"
	"gitee.com/jason_elva8325/micro-quickstart/pb"
	"github.com/go-kit/kit/log"
	grpctransport "github.com/go-kit/kit/transport/grpc"
	oldcontext "golang.org/x/net/context"
	"google.golang.org/grpc/metadata"
)

type grpcServer struct {
	sayHello  grpctransport.Handler
	sayGoodby grpctransport.Handler
}

// NewGRPCServer 新建GRPC服务器方法
func NewGRPCServer(endpoints endpoint.Set, logger log.Logger) pb.SayServiceServer {
	options := []grpctransport.ServerOption{
		grpctransport.ServerErrorLogger(logger),
	}

	// 以下实为协议转码过程
	return &grpcServer{
		sayHello: grpctransport.NewServer(
			endpoints.SayHelloEndpoint,
			decodeGRPCSayHelloRequest,
			encodeGRPCSayHelloResponse,
			append(options, grpctransport.ServerBefore(GRPCToContext()))...,
		),
		sayGoodby: grpctransport.NewServer(
			endpoints.SayGoodbyEndpoint,
			decodeGRPCSayGoodbyRequest,
			encodeGRPCSayGoodbyResponse,
			append(options, grpctransport.ServerBefore(GRPCToContext()))...,
		),
	}
}

func (s grpcServer) SayHello(ctx oldcontext.Context, req *pb.SayHelloRequest) (*pb.SayHelloResponse, error) {
	_, rep, err := s.sayHello.ServeGRPC(ctx, req)
	if err != nil {
		return nil, err
	}
	return rep.(*pb.SayHelloResponse), nil
}

func (s grpcServer) SayGoodby(ctx oldcontext.Context, req *pb.SayGoodbyRequest) (*pb.SayGoodbyResponse, error) {
	_, rep, err := s.sayGoodby.ServeGRPC(ctx, req)
	if err != nil {
		return nil, err
	}
	return rep.(*pb.SayGoodbyResponse), nil
}

func decodeGRPCSayHelloRequest(_ context.Context, grpcReq interface{}) (interface{}, error) {
	req := grpcReq.(*pb.SayHelloRequest)
	return endpoint.SayHelloRequest{Lang: req.Lang, Target: req.Target}, nil
}

func encodeGRPCSayHelloResponse(_ context.Context, response interface{}) (interface{}, error) {
	resp := response.(endpoint.SayHelloResponse)
	return &pb.SayHelloResponse{V: resp.V}, resp.Err
}

func decodeGRPCSayGoodbyRequest(_ context.Context, grpcReq interface{}) (interface{}, error) {
	req := grpcReq.(*pb.SayGoodbyRequest)
	return endpoint.SayGoodbyRequest{Lang: req.Lang, Target: req.Target}, nil
}

func encodeGRPCSayGoodbyResponse(_ context.Context, response interface{}) (interface{}, error) {
	resp := response.(endpoint.SayGoodbyResponse)
	return &pb.SayGoodbyResponse{V: resp.V}, resp.Err
}

// GRPCToContext 将GRPC中的metadata信息转换为上下文信息
func GRPCToContext() grpctransport.ServerRequestFunc {
	return func(ctx context.Context, md metadata.MD) context.Context {
		// capital "Key" is illegal in HTTP/2.
		sessionIDHeader, ok := md["sessionid"]
		if ok && len(sessionIDHeader) == 1 {
			return context.WithValue(ctx, common.ContextKey, sessionIDHeader[0])
		}
		return context.WithValue(ctx, common.ContextKey, "")
	}
}
